<?php
/**
 * @package trading
 */
class CompanyTradeRequest extends DataObject implements PermissionProvider {
    private static $singular_name = "Company Trade Request";
    private static $plural_name = "Company Trade Requests";

    private static $db = array(
    	'Type' => "Enum(array('Buy', 'Sell'))",
    	'Reference' => 'Varchar',
        'Unit' => 'Int',
        'Price' => 'TradeCurrency',
        'ReceiverFee' => 'TradeCurrency'
    );

    private static $has_one = array(
        'Requester' => 'Member',
        'Receiver' => 'Member',
        'TradeSetting' => 'TradeSetting'
    );
	
	private static $many_many = array(
		'TradeCoinAccounts' => 'TradeCoinAccount',
		'TradeHistories' => 'TradeHistory'
	);

    private static $default_sort = "Created DESC";

    private static $searchable_fields = array(
    	'Created' => array(
			'field' => 'DateField',
			'filter' => 'DateMatchFilter'
		),
    	'Requester.Username',
    	'Requester.FirstName',
    	'Requester.Surname',
    	'Receiver.Username',
    	'Receiver.FirstName',
    	'Receiver.Surname',
        'Unit' => array(
            'filter' => 'GreaterThanOrEqualFilter'
        ),
        'Price' => array(
            'filter' => 'GreaterThanOrEqualFilter'
        )
    );

    private static $summary_fields = array(
    	'Requester.Username',
    	'Requester.Name',
    	'Receiver.Username',
    	'Receiver.Name',
    	'Created.Nice',
        'Unit',
        'Price',
        'ReceiverFee'
    );
	
	private static $casting = array(
		'Amount' => 'TradeCurrency'
	);
	
	/**
     * Generate reference for trade request
     * @return str Returns the reference
     */
    static function reference_generator() {
        $reference = rand(1, 99999999);
        $reference = str_pad($reference, 8, "0", STR_PAD_LEFT);
        while($result = CompanyTradeRequest::get()->filter('Reference', $reference)->count()) {
            $reference = rand(1, 999999999);
            $reference = str_pad($reference, 8, "0", STR_PAD_LEFT);
        }
        return $reference;
    }

	public function populateDefaults() {
        parent::populateDefaults();
		$this->RequesterID = Member::currentUserID();
    }

    public function fieldLabels($includerelations = true) {
        $labels = parent::fieldLabels($includerelations);

		$labels['Created'] = _t('CompanyTradeRequest.DATE', 'Date');
		$labels['Created.Nice'] = _t('CompanyTradeRequest.DATE', 'Date');
		$labels['Type'] = _t('CompanyTradeRequest.TYPE', 'Type');
		$labels['Reference'] = _t('CompanyTradeRequest.REFERENCE', 'Reference');
        $labels['Unit'] = _t('CompanyTradeRequest.UNIT', 'Unit');
        $labels['Price'] = _t('CompanyTradeRequest.PRICE', 'Price');
		$labels['ReceiverFee'] = _t('CompanyTradeRequest.RECEIVER_FEE', 'Receiver Fee');
		$labels['TradeSetting'] = _t('CompanyTradeRequest.TRADE_SETTING', 'Trade Setting');
		$labels['TradeSettingID'] = _t('CompanyTradeRequest.TRADE_SETTING', 'Trade Setting');
		$labels['Requester.Username'] = _t('CompanyTradeRequest.USERNAME', 'Username');
		$labels['Requester.FirstName'] = _t('CompanyTradeRequest.FIRST_NAME', 'First Name');
		$labels['Requester.Surname'] = _t('CompanyTradeRequest.SURNAME', 'Surname');
		$labels['Requester.Name'] = _t('CompanyTradeRequest.NAME', 'Name');
		$labels['Receiver.Username'] = _t('CompanyTradeRequest.USERNAME', 'Username');
		$labels['Receiver.FirstName'] = _t('CompanyTradeRequest.FIRST_NAME', 'First Name');
		$labels['Receiver.Surname'] = _t('CompanyTradeRequest.SURNAME', 'Surname');
		$labels['Receiver.Name'] = _t('CompanyTradeRequest.NAME', 'Name');

        return $labels;
    }

    function validate() {
        $validationResult = parent::validate();

		if($this->ReceiverUsername && !$this->ReceiverID){
			$this->ReceiverID = Distributor::get_id_by_username($this->ReceiverUsername);
		}
		
        if(!$this->RequesterID) {
            $subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INVALID_REQUESTER_ID', 'Invalid Requester ID'), 'INVALID_REQUESTER_ID');
            $validationResult->combineAnd($subvalid);
        }
		
		if(!$this->ReceiverID) {
            $subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INVALID_RECEIVER_ID', 'Invalid Receiver ID'), 'INVALID_RECEIVER_ID');
            $validationResult->combineAnd($subvalid);
        }

        if($this->Unit <= 0) {
            $subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INVALID_TRADE_UNIT', 'Invalid trade unit'), 'INVALID_TRADE_UNIT');
            $validationResult->combineAnd($subvalid);
        }

        if($this->Price <= 0) {
            $subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INVALID_TRADE_PRICE', 'Invalid trade price'), 'INVALID_TRADE_PRICE');
            $validationResult->combineAnd($subvalid);
        }
		
		if($this->ReceiverFee < 0) {
            $subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INVALID_RECEIVER_TRADE_FEE', 'Invalid receiver trade fee'), 'INVALID_RECEIVER_TRADE_FEE');
            $validationResult->combineAnd($subvalid);
        }

		if(!$this->TradeSettingID) {
            $subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INVALID_TRADE_SETTING_ID', 'Invalid trade setting id'), 'INVALID_TRADE_SETTING_ID');
            $validationResult->combineAnd($subvalid);
        }

		if($this->Type == 'Sell' && ($this->Amount + $this->ReceiverFee) > $this->Receiver()->TradeCoinAccountBalance){
			$subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INSUFFICIENT_TRADE_COIN_BALANCE', "Insufficient Trade-Coin balance"), "INSUFFICIENT_TRADE_COIN_BALANCE");
            $validationResult->combineAnd($subvalid);
		}
		
		if($this->Type == 'Buy' && $this->Unit > $this->Receiver()->TradeAccount($this->TradeSettingID)->CurrentUnit){
			$subvalid = new ValidationResult();
            $subvalid->error(_t('CompanyTradeRequest.INSUFFICIENT_TRADE_UNIT', "Insufficient trade unit"), "INSUFFICIENT_TRADE_UNIT");
            $validationResult->combineAnd($subvalid);
		}

        return $validationResult;
    }

	function getCMSFields() {
		$fields = parent::getCMSFields();
		if($this->exists()) {
            $fields->makeFieldReadonly('RequesterID');
            $fields->makeFieldReadonly('ReceiverID');
			$fields->removeByName('TradeCoinAccounts');
			$fields->removeByName('TradeHistories');
        } else {
        	$fields->removeByName('Reference');
			$fields->removeByName('ReceiverID');
            $fields->insertAfter(UsernameField::create('ReceiverUsername', $this->fieldLabel('Receiver.Username')), 'Type');
        }
        $fields->removeByName('RequesterID');
		return $fields;
	}

	function onBeforeWrite() {
        parent::onBeforeWrite();
        if($this->Reference == '') {
            $this->Reference = self::reference_generator();
        }
		
		if(!$this->ReceiverID && $this->ReceiverUsername != ''){
			$this->ReceiverID = Distributor::get_id_by_username($this->ReceiverUsername);
		}
    }

	function onAfterWrite() {
        parent::onAfterWrite();
		
        if($this->isChanged('ID') && $this->Amount > 0){
        	if($this->Type == 'Buy'){
	        	$trade_history = TradeHistory::create();
				$trade_history->Type = 'Sell';
				$trade_history->Reference = $this->Reference;
				$trade_history->Unit = $this->Unit;
				$trade_history->Price = $this->Price;
				$trade_history->Fee = $this->ReceiverFee;
				$trade_history->MemberID = $this->ReceiverID;
				$trade_history->TradeSettingID = $this->TradeSettingID;
				$trade_history->IsCompany = 1;
				$trade_history->write();
				$this->TradeHistories()->add($trade_history);
				
				$statement_data = array(
		            'Type' => 'Sell Share (Company)',
		            'Credit' => $this->Amount - $this->ReceiverFee,
		            'Reference' => $this->Reference,
		            'Description' => sprintf('Sell %s units of %s share at %s per unit. Fees %s, %s receivable.', $this->dbObject('Unit')->Formatted(), $this->Name, $this->dbObject('Price')->Nice(), $this->dbObject('ReceiverFee')->Nice(), DBField::create_field('Percentage', 0.3)->Nice())
		        );
		    	$id = TradeCoinAccount::create_statement($statement_data, $this->ReceiverID);
				$this->TradeCoinAccounts()->add($id);
			}
			
			if($this->Type == 'Sell'){
				$trade_history = TradeHistory::create();
				$trade_history->Type = 'Buy';
				$trade_history->Reference = $this->Reference;
				$trade_history->Unit = $this->Unit;
				$trade_history->Price = $this->Price;
				$trade_history->Fee = $this->ReceiverFee;
				$trade_history->MemberID = $this->ReceiverID;
				$trade_history->TradeSettingID = $this->TradeSettingID;
				$trade_history->IsCompany = 1;
				$trade_history->write();
				$this->TradeHistories()->add($trade_history);
				
	    		$statement_data = array(
	                'Type' => 'Buy Share (Company)',
	                'Debit' => $this->Amount + $this->ReceiverFee,
	                'Reference' => $this->Reference,
	                'Description' => sprintf('Buy order with %s units at price %s of share %s. Fees %s.', $this->dbObject('Unit')->Formatted(), $this->dbObject('Price')->Nice(), $this->Name, $this->obj('ReceiverFee')->Nice())
	            );
	        	$id = TradeCoinAccount::create_statement($statement_data, $this->ReceiverID);
				$this->TradeCoinAccounts()->add($id);
			}
        }
    }
	
	function getName(){
		return $this->TradeSetting()->Title;
	}
	
	function getAmount(){
		return $this->Price * $this->Unit;
	}
	
	function canView($member = false) {
        $extended = $this->extendedCan(__FUNCTION__, $member);
        if($extended !== null) {
            return $extended;
        }
        return Permission::check('VIEW_CompanyTradeRequest');
    }

    function canEdit($member = false) {
    	if(!$this->exists() && $this->canCreate($member)){
    		return true;
    	}
        return false;
    }

    function canDelete($member = false) {
        return false;
    }

    function canCreate($member = false) {
        $extended = $this->extendedCan(__FUNCTION__, $member);
        if($extended !== null) {
            return $extended;
        }
        return Permission::check('CREATE_CompanyTradeRequest');
    }

    public function providePermissions() {
        return array(
            'VIEW_CompanyTradeRequest' => array(
                'name' => _t('CompanyTradeRequest.PERMISSION_VIEW', 'Allow view access right'),
                'category' => _t('CompanyTradeRequest.PERMISSIONS_CATEGORY', 'Company Trade Request')
            ),
            'CREATE_CompanyTradeRequest' => array(
                'name' => _t('CompanyTradeRequest.PERMISSION_CREATE', 'Allow create access right'),
                'category' => _t('CompanyTradeRequest.PERMISSIONS_CATEGORY', 'Company Trade Request')
            )
        );
    }
}
?>